//
//  BSCoreLocation.m
//  BASE_LIB
//
//  Created by shiji on 2018/3/13.
//  Copyright © 2018年 shiji. All rights reserved.
//

#import "BSCoreLocation.h"
#import <CoreLocation/CoreLocation.h>
#import <UIKit/UIKit.h>

#define kLocation @"com.lastlocation.cn"
#define lastLocation(folderName)                        [[NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask,   YES) objectAtIndex:0] stringByAppendingPathComponent:folderName]

@interface BSCoreLocation ()<CLLocationManagerDelegate>
@property (nonatomic, strong) CLLocationManager *locationManager;

@property (nonatomic, assign) CLLocationAccuracy LocationAccuracy;

@property (nonatomic, copy)   LocationUpdateBlock locationBlock;

@property (nonatomic, copy)   HeadingUpdateBlock headingBlock;

@property (nonatomic, strong) CLLocation *currentLocations;

@property (nonatomic, strong) CLLocation *lastLocations;

@end

@implementation BSCoreLocation
@synthesize currentLocations = _currentLocations;
@synthesize lastLocations = _lastLocations;

+ (instancetype)shared {
    static dispatch_once_t onceToken;
    static BSCoreLocation *shared = nil;
    dispatch_once(&onceToken, ^{
        shared = [BSCoreLocation new];
    });
    return shared;
}

- (void)dealloc {
    [self stop];
}

- (instancetype)init
{
    self = [super init];
    if (self) {
        self.locService = LocServiceLocationService;
        self.locAccuracy = LocationAccuracyUnKnown;
        self.disFilter = 10.0f;
    }
    return self;
}

- (void)start {
    if ([CLLocationManager locationServicesEnabled]) {
        //控制定位精度,越高耗电量越
        self.locationManager.desiredAccuracy = self.LocationAccuracy;
        // 总是授权
        [self.locationManager requestAlwaysAuthorization];
        self.locationManager.distanceFilter = self.disFilter;
        [self.locationManager startUpdatingLocation];
        if (self.locService | LocServiceHeadingAvailable) {
            if ([CLLocationManager headingAvailable]) {
                [self.locationManager startUpdatingHeading];
            }
        }
    }
}

- (void)start:(LocationUpdateBlock)block {
    self.locationBlock = block;
    [self start];
}

- (void)start:(LocationAccuracy)accuracy block:(LocationUpdateBlock)block {
    self.locAccuracy = accuracy;
    self.locationBlock = block;
    [self start];
}

- (void)start:(LocationAccuracy)accuracy distanceFilter:(LOC_DOUBLE)distanceFilter block:(LocationUpdateBlock)block {
    self.locAccuracy = accuracy;
    self.disFilter = distanceFilter;
    self.locationBlock = block;
    [self start];
}

- (void)start:(LocationAccuracy)accuracy
distanceFilter:(LOC_DOUBLE)distanceFilter
   locService:(LocService)locService
     locBlock:(LocationUpdateBlock)locBlock
 headingBlock:(HeadingUpdateBlock)headingBlock{
    self.locAccuracy = accuracy;
    self.disFilter = distanceFilter;
    self.locService = locService;
    self.locationBlock = locBlock;
    self.headingBlock = headingBlock;
    [self start];
}

- (void)stop {
    if (self.locService | LocServiceLocationService) {
        [self.locationManager stopUpdatingLocation];
    }
    if (self.locService | LocServiceHeadingAvailable) {
        [self.locationManager stopUpdatingHeading];
    }
}



- (CLLocationAccuracy )locationAccuracy {
    switch (self.locAccuracy) {
        case LocationAccuracyUnKnown:
            return kCLLocationAccuracyBest;
            break;
        case LocationAccuracyBestForNavigation:
            return kCLLocationAccuracyBestForNavigation;
            break;
        case LocationAccuracyBest:
            return kCLLocationAccuracyBest;
            break;
        case LocationAccuracyNearestTenMeters:
            return kCLLocationAccuracyNearestTenMeters;
            break;
        case LocationAccuracyHundredMeters:
            return kCLLocationAccuracyHundredMeters;
            break;
        case LocationAccuracyKilometer:
            return kCLLocationAccuracyKilometer;
            break;
        case LocationAccuracyThreeKilometers:
            return kCLLocationAccuracyThreeKilometers;
            break;
        default:
            return kCLLocationAccuracyBest;
            break;
    }
}

- (CLLocationManager *)locationManager{
    if (!_locationManager) {
        _locationManager = [[CLLocationManager alloc]init];
        _locationManager.delegate = self;
    }
    return _locationManager;
}

#pragma mark -CLLocationManagerDelegate-
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations {
    self.lastLocations = locations.firstObject;
    self.currentLocations = locations.firstObject;
    self.locationBlock(locations.firstObject);
}

- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status {
    if (status == kCLAuthorizationStatusNotDetermined && [manager respondsToSelector:@selector(requestAlwaysAuthorization)]) {
        [manager requestWhenInUseAuthorization];
    }
}

- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
    CLAuthorizationStatus state = [CLLocationManager authorizationStatus];
    if (![CLLocationManager locationServicesEnabled] || (state != kCLAuthorizationStatusAuthorizedAlways && state != kCLAuthorizationStatusAuthorizedWhenInUse)) {
        [self stop];
    }
}

// 获得地理和地磁航向数据，从而转动地理刻度表
- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading {
    // 判断磁力计是否有效,负数时为无效，越小越精确
    if (newHeading.headingAccuracy > 0) {
        self.headingBlock(newHeading);
    }
}

- (BOOL)locationManagerShouldDisplayHeadingCalibration:(CLLocationManager *)manager {
    return YES;
}

#pragma  - mark getter setter -
- (void)setLastLocations:(CLLocation *)lastLocations {
    _lastLocations = lastLocations;
    [NSKeyedArchiver archiveRootObject:lastLocations toFile:lastLocation(kLocation)];
}

- (CLLocation *)lastLocations {
    if (!_lastLocations) {
        return [NSKeyedUnarchiver unarchiveObjectWithFile:lastLocation(kLocation)];
    }
    return _lastLocations;
}

@end
